/**
 * 
 */
package org.rollinitiative.d20web.gmportal.client;

import java.util.ArrayList;
import java.util.HashMap;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DecoratedStackPanel;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * Basic concept for this view is a listing of all potential combatants for the encounter organized
 * by faction. Anticipate using an accordion widget for the factions with each faction containing a
 * listing of its combatants.
 * 
 * @author bebopjmm
 * 
 */
public class CombatantsView extends Composite implements ClickListener
{
    VerticalPanel partyPanel = new VerticalPanel();

    VerticalPanel hostilePanel = new VerticalPanel();

    VerticalPanel neutralPanel = new VerticalPanel();

    VerticalPanel alliesPanel = new VerticalPanel();

    private EncounterServiceAsync encounterService;

    private String encounterID;

    private ArrayList<CombatantListener> listeners = new ArrayList<CombatantListener>();

    private HashMap<String, CombatantData> combatantMap = new HashMap<String, CombatantData>();

    private InitiativeDialog initDialog = new InitiativeDialog();


    public CombatantsView()
    {
        encounterService = (EncounterServiceAsync) GWT.create(EncounterService.class);
        ServiceDefTarget endpoint = (ServiceDefTarget) encounterService;
        String moduleRelativeURL = GWT.getModuleBaseURL() + "EncounterManagementService";
        endpoint.setServiceEntryPoint(moduleRelativeURL);

        VerticalPanel panel = new VerticalPanel();
        DecoratedStackPanel factionPanel = new DecoratedStackPanel();

        partyPanel.setTitle("Party");
        partyPanel.setWidth("100%");
        factionPanel.add(partyPanel, "Party");
        hostilePanel.setTitle("Hostiles");
        hostilePanel.setWidth("100%");
        factionPanel.add(hostilePanel, "Hostiles");
        neutralPanel.setTitle("Neutrals");
        neutralPanel.setWidth("100%");
        factionPanel.add(neutralPanel, "Neutrals");
        alliesPanel.setTitle("Allies");
        alliesPanel.setWidth("100%");
        factionPanel.add(alliesPanel, "Allies");

        VerticalPanel bestiaryPanel = new VerticalPanel();
        bestiaryPanel.add(new Label("Tree of potential adversary types"));
        bestiaryPanel.setWidth("100%");
        factionPanel.add(bestiaryPanel, "Bestiary");
        factionPanel.setWidth("100%");

        panel.add(factionPanel);
        panel.setWidth("100%");

        // Notify All Combatant Listeners when a Combatant has been initiated for the encounter
        initDialog.addListener(new ClickListener() {
            public void onClick(Widget sender)
            {
                for (CombatantListener listener : listeners) {
                    listener.combatantAware(initDialog.combatant);
                }
            }
        });

        initWidget(panel);
    }


    public void setEncounterID(String encounterID)
    {
        this.encounterID = encounterID;
    }


    public void addCombatantListener(CombatantListener listener)
    {
        if (listeners.contains(listener)) {
            return;
        }
        listeners.add(listener);
    }


    /*
     * (non-Javadoc)
     * 
     * @see
     * com.google.gwt.user.client.ui.ClickListener#onClick(com.google.gwt.user.client.ui.Widget)
     */
    public void onClick(Widget sender)
    {
        // TODO Auto-generated method stub
        String name = ((CheckBox) sender).getText();
        GWT.log("Click on:" + name, null);
        if (((CheckBox) sender).isChecked()) {
            // Generate Join Event to EncounterService.
            GWT.log("Initiating Combatant for encounter:" + name, null);
            CombatantData combatant = combatantMap.get(name);
            // TODO DialogBox for entering or rolling initiative value
            initDialog.reset(combatant);
            initDialog.show();
        }

    }

    AsyncCallback<CombatantData> addCombatantCallback = new AsyncCallback<CombatantData>() {
        public void onSuccess(CombatantData result)
        {
            addCombatant(result);
        }


        public void onFailure(Throwable caught)
        {
            GWT.log("Call for adding combatant failed", caught);
        }
    };


    private void addCombatant(CombatantData newCombatant)
    {
        combatantMap.put(newCombatant.getCombatantName(), newCombatant);

        String faction = newCombatant.getFactionName();
        VerticalPanel panel = null;
        if (faction.equalsIgnoreCase("party")) {
            panel = partyPanel;
        }
        else if (faction.equalsIgnoreCase("hostiles")) {
            panel = hostilePanel;
        }
        else if (faction.equalsIgnoreCase("allies")) {
            panel = alliesPanel;
        }
        else {
            panel = neutralPanel;
        }
        CheckBox entry = new CheckBox(newCombatant.getCombatantName());
        entry.setChecked(false);
        entry.addClickListener(this);
        panel.add(entry);
    }


    public void loadDefaultData()
    {
        encounterService.addCombatant(encounterID, "Cyril", EncounterService.PARTY_FACTION,
                addCombatantCallback);
        encounterService.addCombatant(encounterID, "Rena", EncounterService.PARTY_FACTION,
                addCombatantCallback);
        encounterService.addCombatant(encounterID, "Zaryn", EncounterService.PARTY_FACTION,
                addCombatantCallback);

        encounterService.addCombatant(encounterID, "Orc (1)", EncounterService.HOSTILES_FACTION,
                addCombatantCallback);

        encounterService.addCombatant(encounterID, "Commoner (1)",
                EncounterService.NEUTRALS_FACTION, addCombatantCallback);

        encounterService.addCombatant(encounterID, "Town Guard (1)",
                EncounterService.ALLIES_FACTION, addCombatantCallback);
    }

    private static class InitiativeDialog extends DialogBox
    {
        public CombatantData combatant;

        Button okButton;

        private final TextBox hpText = new TextBox();

        private final TextBox initBaseText = new TextBox();

        private final TextBox initModText = new TextBox();

        private final RadioButton rollInitChoice = new RadioButton("initiativeGroup",
                "Auto-roll Initiative");

        private final RadioButton setInitChoice = new RadioButton("initiativeGroup",
                "Assign Initiative");


        public InitiativeDialog()
        {
            setTitle("Initiative Dialog");
            setText("Initiative Dialog");

            Grid grid = new Grid(6, 3);

            grid.setWidget(0, 0, rollInitChoice);
            grid.setWidget(1, 0, setInitChoice);
            grid.setWidget(2, 1, new Label("Base:"));
            grid.setWidget(2, 2, initBaseText);
            grid.setWidget(3, 0, new Label("Mods:"));
            grid.setWidget(3, 1, initModText);

            grid.setWidget(4, 0, new Label("Hit Points:"));
            grid.setWidget(4, 1, hpText);

            okButton = new Button("OK");
            okButton.addClickListener(new ClickListener() {
                public void onClick(Widget sender)
                {
                    if (rollInitChoice.isChecked()) {
                        combatant.setInitiativeBase(-1);
                    }
                    else {
                        combatant.setInitiativeBase(Integer.parseInt(initBaseText.getText()));
                    }
                    combatant.setInitiativeMod(Integer.parseInt(initModText.getText()));
                    combatant.setHitPoints(Integer.parseInt(hpText.getText()));
                    combatant.setAware(true);
                    InitiativeDialog.this.hide();
                }
            });
            grid.setWidget(5, 2, okButton);
            setWidget(grid);
        }


        public void addListener(ClickListener listener)
        {
            okButton.addClickListener(listener);
        }


        public void reset(CombatantData combatant)
        {
            this.combatant = combatant;
        }
    }
}
